/*
 * JGO2RDF creates a RDF representation of GAF2 files, which are automatically sourced from GO ftp site.
 * Copyright (C) 2012 Matthew M. Hindle & Artem Lysenko
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package uk.co.jgo2rdf.goa.go;

import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.ProfileRegistry;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.vocabulary.RDFS;
import org.apache.log4j.Logger;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author hindlem
 *         Date: 5/12/11
 *         Time: 10:29 AM
 * @version 0.10
 */
public class GOECIndex {

    private static final Logger log = Logger.getLogger(GOECIndex.class);

    private final Map<String, String> label2URI = new HashMap<String, String>();

    private static WeakReference<GOECIndex> INSTANCE = new WeakReference<GOECIndex>(null);

    public static synchronized GOECIndex getInstance() {
        GOECIndex index = INSTANCE.get();

        if (index != null)
            return index;

        synchronized (GOECIndex.class) {
            index = INSTANCE.get();
            if (index != null)
                return index;

            index = new GOECIndex(); // creates new instnace
            INSTANCE = new WeakReference<GOECIndex>(index);

        }
        return index;
    }

    private GOECIndex() {
        index();
    }

    private void index() {
        OntModel m = ModelFactory.createOntologyModel(ProfileRegistry.OWL_LANG);
        m.setDynamicImports(true);
        m.setStrictMode(false);
        m.read("http://www.berkeleybop.org/ontologies/owl/ECO");

        Set<String> blacklist = new HashSet<String>();

        Property exactSynonym = m.getProperty("http://www.geneontology.org/formats/oboInOwl#hasExactSynonym");
        //Resource synonym = m.getResource("http://www.geneontology.org/formats/oboInOwl#Synonym");

        Set<OntClass> classes = m.listClasses().toSet();
        for (OntClass owlClass : classes) {
            if (owlClass.hasProperty(exactSynonym)) {
                StmtIterator statements = owlClass.listProperties(exactSynonym);

                //System.out.println(owlClass.getURI());
                while (statements.hasNext()) {
                    Statement statement = statements.nextStatement();
                    Resource synonym = statement.getResource();
                    String label = synonym.getProperty(RDFS.label).getString();
                    //System.out.println(label);
                    if (!label2URI.containsKey(label) && !blacklist.contains(label)) {
                        label2URI.put(label, owlClass.getURI());
                    } else {
                        label2URI.remove(label);
                        blacklist.add(label);
                        log.error(label + " has been black listed");
                    }
                }
            }

        }
    }

    private static final Model m_model = ModelFactory.createDefaultModel();

    public boolean hasTranslationForEvidenceCode(String code) {
        if (label2URI.containsKey(code)) {
            return true;
        }
        return label2URI.containsKey("GO:" + code);
    }

    public Resource getResourceForEvidenceCode(String code) {
        String uri = label2URI.get(code);
        if (uri == null)
            uri = label2URI.get("GO:" + code);
        if (uri == null) {
            log.error("No translation found for " + code);
            return null;
        }
        return m_model.createResource(uri);
    }

}
